package com.hitomi.smlibrary;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.StackLayout;

/**
 * 菜单打开/关闭动画 <br/>
 * <p>
 * Created by hitomi on 2016/9/19. <br/>
 * <p>
 * github : https://github.com/Hitomis <br/>
 * <p>
 * email : 196425254@qq.com
 */
public class SpinMenuAnimator {

    private final int interpolator = Animator.CurveType.OVERSHOOT;

    private SpinMenuLayout spinMenuLayout;

    private SpinMenu spinMenu;

    private OnSpinMenuStateChangeListener onSpinMenuStateChangeListener;

    private float diffTranY;

    public SpinMenuAnimator(SpinMenu spinMenu, SpinMenuLayout spinMenuLayout, OnSpinMenuStateChangeListener listener) {
        this.spinMenu = spinMenu;
        this.spinMenuLayout = spinMenuLayout;
        this.onSpinMenuStateChangeListener = listener;
    }

    public void openMenuAnimator() {
        // 打开菜单之前，将菜单状态更新为 MENU_STATE_OPEN 并且显示 SpinMenuLayout
        spinMenu.updateMenuState(SpinMenu.MENU_STATE_OPEN);
        spinMenuLayout.setVisibility(Component.VISIBLE);

        ComponentContainer selectItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(spinMenuLayout.getSelectedPosition());
        final ComponentContainer showingPager = (ComponentContainer) spinMenu.getComponentAt(spinMenu.getChildCount() - 1);
        final ComponentContainer selectContainer = (ComponentContainer) selectItemLayout.findComponentById(SpinMenu.TAG_ITEM_CONTAINER_ID);
        final float scaleRatio = spinMenu.getScaleRatio();
        diffTranY = (showingPager.getHeight() * (1.f - scaleRatio)) * .5f - selectItemLayout.getTranslationY();

        // 获取当前菜单中间位置左边的菜单项，并设置右移动画
        AnimatorValue leftTranXAnima = null, rightTranXAnima = null;
        if (spinMenuLayout.getSelectedPosition() - 1 > -1) {
            ComponentContainer leftItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(spinMenuLayout.getSelectedPosition() - 1);
            leftTranXAnima = new AnimatorValue();
            leftTranXAnima.setDuration(300);
            leftTranXAnima.setCurveType(interpolator);
            final float start = leftItemLayout.getTranslationX() - SpinMenu.TRAN_SKNEW_VALUE;
            final float end = leftItemLayout.getTranslationX();
            leftTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float translationX = start + (end - start) * v;
                leftItemLayout.setTranslationX(translationX);
            });
        } else if (spinMenuLayout.isCyclic() && spinMenuLayout.getSelectedPosition() == 0) {
            ComponentContainer leftItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(spinMenuLayout.getMenuItemCount() - 1);
            leftTranXAnima = new AnimatorValue();
            leftTranXAnima.setDuration(300);
            leftTranXAnima.setCurveType(interpolator);
            final float start = leftItemLayout.getTranslationX() - SpinMenu.TRAN_SKNEW_VALUE;
            final float end = leftItemLayout.getTranslationX();
            leftTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float translationX = start + (end - start) * v;
                leftItemLayout.setTranslationX(translationX);
            });
        }

        // 获取当前菜单中间位置右边的菜单项，并设置左移动画
        if (spinMenuLayout.getSelectedPosition() + 1 < spinMenuLayout.getChildCount()) {
            ComponentContainer rightItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(spinMenuLayout.getSelectedPosition() + 1);
            rightTranXAnima = new AnimatorValue();
            rightTranXAnima.setDuration(300);
            rightTranXAnima.setCurveType(interpolator);
            final float start = rightItemLayout.getTranslationX() + SpinMenu.TRAN_SKNEW_VALUE;
            final float end = rightItemLayout.getTranslationX();
            rightTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float translationX = start + (end - start) * v;
                rightItemLayout.setTranslationX(translationX);
            });
        } else if (spinMenuLayout.isCyclic() && spinMenuLayout.getSelectedPosition() + 1 == spinMenuLayout.getMenuItemCount()) {
            ComponentContainer rightItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(0);
            rightTranXAnima = new AnimatorValue();
            rightTranXAnima.setDuration(300);
            rightTranXAnima.setCurveType(interpolator);
            final float start = rightItemLayout.getTranslationX() + SpinMenu.TRAN_SKNEW_VALUE;
            final float end = rightItemLayout.getTranslationX();
            rightTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float translationX = start + (end - start) * v;
                rightItemLayout.setTranslationX(translationX);
            });
        }

        // 设置当前页面的缩放和上移动画
        AnimatorValue scaleXAnima = new AnimatorValue();
        scaleXAnima.setDuration(300);
        scaleXAnima.setCurveType(interpolator);
        float startScaleX = showingPager.getScaleX();
        float endScaleX = scaleRatio;
        scaleXAnima.setValueUpdateListener((animatorValue, v) -> {
            float scaleX = startScaleX + (endScaleX - startScaleX) * v;
            showingPager.setScaleX(scaleX);
        });
        AnimatorValue scaleYAnima = new AnimatorValue();
        scaleYAnima.setDuration(300);
        scaleYAnima.setCurveType(interpolator);
        float startScaleY = showingPager.getScaleY();
        float endScaleY = scaleRatio;
        scaleYAnima.setValueUpdateListener((animatorValue, v) -> {
            float scaleY = startScaleY + (endScaleY - startScaleY) * v;
            showingPager.setScaleY(scaleY);
        });
        AnimatorValue tranYAnima = new AnimatorValue();
        tranYAnima.setDuration(300);
        tranYAnima.setCurveType(interpolator);
        float startTranY = showingPager.getTranslationY();
        float endTranY = -diffTranY;
        tranYAnima.setValueUpdateListener((animatorValue, v) -> {
            float tranY = startTranY + (endTranY - startTranY) * v;
            showingPager.setTranslationY(tranY);
        });

        AnimatorGroup animatorGroup = new AnimatorGroup();
        animatorGroup.setDuration(300);
        animatorGroup.setCurveType(interpolator);
        AnimatorGroup.Builder builder = animatorGroup.build();
        if (leftTranXAnima != null && rightTranXAnima != null) {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranYAnima, leftTranXAnima, rightTranXAnima);
        } else if (leftTranXAnima != null) {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranYAnima, leftTranXAnima);
        } else if (rightTranXAnima != null) {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranYAnima, rightTranXAnima);
        } else {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranYAnima);
        }
        animatorGroup.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                StackLayout.LayoutConfig pagerParams = new StackLayout.LayoutConfig(
                        showingPager.getWidth(),
                        showingPager.getHeight()
                );
                spinMenu.removeComponent(showingPager);

                // 从 selectContainer 中移除之前用来占位的 FrameLayout
                selectContainer.removeAllComponents();

                // 将 showingPager 添加到 selectContainer 中

                selectContainer.addComponent(showingPager, pagerParams);

                // 校正 showingPager 在 selectContainer 中的位置
                float tranX = (showingPager.getWidth() * (1.f - scaleRatio)) * .5f;
                float tranY = (showingPager.getHeight() * (1.f - scaleRatio)) * .5f;

                showingPager.setTranslationX(-tranX);
                showingPager.setTranslationY(-tranY);

                ClickUtils.setChildClickable(showingPager, false);

                if (onSpinMenuStateChangeListener != null) {
                    onSpinMenuStateChangeListener.onMenuOpened();
                }

                // 菜单打开后，允许滑动控制 spinMenuLayout 转动。且更新菜单状态为 MENU_STATE_OPENED
                spinMenuLayout.postEnable(true);
                spinMenu.updateMenuState(SpinMenu.MENU_STATE_OPENED);
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        animatorGroup.start();
    }

    public void closeMenuAnimator(SMItemLayout chooseItemLayout) {
        // 关闭菜单之前更新菜单状态为 MENU_STATE_CLOSE，并且不允许滑动控制 spinMenuLayout 转动
        spinMenu.updateMenuState(SpinMenu.MENU_STATE_CLOSE);
        spinMenuLayout.postEnable(false);

        // 从 chooseItemLayout 中移除包含显示 Fragment 的 FrameLayout
        StackLayout frameContainer = (StackLayout) chooseItemLayout.findComponentById(SpinMenu.TAG_ITEM_CONTAINER_ID);
        StackLayout pagerLayout = (StackLayout) frameContainer.findComponentById(SpinMenu.TAG_ITEM_PAGER_ID);
        frameContainer.removeComponent(pagerLayout);

        // 创建一个用来占位的 FrameLayout
        StackLayout.LayoutConfig pagerFrameParams = new StackLayout.LayoutConfig(
                StackLayout.LayoutConfig.MATCH_PARENT,
                StackLayout.LayoutConfig.MATCH_PARENT);
        StackLayout holderLayout = new StackLayout(chooseItemLayout.getContext());
        holderLayout.setLayoutConfig(pagerFrameParams);

        // 将占位的 FrameLayout 添加到 chooseItemLayout 布局中的 frameContainer 中
        frameContainer.addComponent(holderLayout);

        // 添加 pagerLayout 添加到 SpinMenu 中
        pagerLayout.setLayoutConfig(pagerFrameParams);
        spinMenu.addComponent(pagerLayout);

        // 放置 pagerLayout 到同一个位置
        int currTranX = (int) (spinMenu.getWidth() * (1.f - spinMenu.getScaleRatio()) * .5f);
        int currTranY = (int) (spinMenu.getHeight() * (1.f - spinMenu.getScaleRatio()) * .5f - diffTranY);
        pagerLayout.setTranslationX(currTranX);
        pagerLayout.setTranslationY(currTranY);
        pagerLayout.setScaleX(spinMenu.getScaleRatio());
        pagerLayout.setScaleY(spinMenu.getScaleRatio());

        // 获取当前菜单中间位置左边的菜单项，并设置左移动画
        AnimatorValue leftTranXAnima = null, rightTranXAnima = null;
        if (spinMenuLayout.getSelectedPosition() - 1 > -1) {
            ComponentContainer leftItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(spinMenuLayout.getSelectedPosition() - 1);
            leftTranXAnima = new AnimatorValue();
            leftTranXAnima.setDuration(300);
            leftTranXAnima.setCurveType(interpolator);
            float start = leftItemLayout.getTranslationX();
            float end = leftItemLayout.getTranslationX() - SpinMenu.TRAN_SKNEW_VALUE;
            leftTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float tranX = start + (end - start) * v;
                leftItemLayout.setTranslationX(tranX);
            });
        } else if (spinMenuLayout.isCyclic() && spinMenuLayout.getSelectedPosition() == 0) {
            ComponentContainer leftItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(spinMenuLayout.getMenuItemCount() - 1);
            leftTranXAnima = new AnimatorValue();
            leftTranXAnima.setDuration(300);
            leftTranXAnima.setCurveType(interpolator);
            float start = leftItemLayout.getTranslationX();
            float end = leftItemLayout.getTranslationX() - SpinMenu.TRAN_SKNEW_VALUE;
            leftTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float tranX = start + (end - start) * v;
                leftItemLayout.setTranslationX(tranX);
            });
        }

        // 获取当前菜单中间位置右边的菜单项，并设置右移动画
        if (spinMenuLayout.getSelectedPosition() + 1 < spinMenuLayout.getChildCount()) {
            ComponentContainer rightItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(spinMenuLayout.getSelectedPosition() + 1);
            rightTranXAnima = new AnimatorValue();
            rightTranXAnima.setDuration(300);
            rightTranXAnima.setCurveType(interpolator);
            float start = rightItemLayout.getTranslationX();
            float end = rightItemLayout.getTranslationX() + SpinMenu.TRAN_SKNEW_VALUE;
            rightTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float tranX = start + (end - start) * v;
                rightItemLayout.setTranslationX(tranX);
            });
        } else if (spinMenuLayout.isCyclic() && spinMenuLayout.getSelectedPosition() + 1 == spinMenuLayout.getMenuItemCount()) {
            ComponentContainer rightItemLayout = (ComponentContainer) spinMenuLayout.getComponentAt(0);
            rightTranXAnima = new AnimatorValue();
            rightTranXAnima.setDuration(300);
            rightTranXAnima.setCurveType(interpolator);
            float start = rightItemLayout.getTranslationX();
            float end = rightItemLayout.getTranslationX() + SpinMenu.TRAN_SKNEW_VALUE;
            rightTranXAnima.setValueUpdateListener((animatorValue, v) -> {
                float tranX = start + (end - start) * v;
                rightItemLayout.setTranslationX(tranX);
            });
        }

        // 设置当前选中菜单的缩放，左右和下移动画
        AnimatorValue scaleXAnima = new AnimatorValue();
        scaleXAnima.setDuration(300);
        scaleXAnima.setCurveType(interpolator);
        float startScaleX = pagerLayout.getScaleX();
        float endScaleX = 1.f;
        scaleXAnima.setValueUpdateListener((animatorValue, v) -> {
            float scaleX = startScaleX + (endScaleX - startScaleX) * v;
            pagerLayout.setScaleX(scaleX);
        });
        AnimatorValue scaleYAnima = new AnimatorValue();
        scaleYAnima.setDuration(300);
        scaleYAnima.setCurveType(interpolator);
        float startScaleY = pagerLayout.getScaleX();
        float endScaleY = 1.f;
        scaleYAnima.setValueUpdateListener((animatorValue, v) -> {
            float scaleY = startScaleY + (endScaleY - startScaleY) * v;
            pagerLayout.setScaleY(scaleY);
        });
        AnimatorValue tranXAnima = new AnimatorValue();
        tranXAnima.setDuration(300);
        tranXAnima.setCurveType(interpolator);
        float startTranX = 0;
        float endTranX = 0;
        pagerLayout.setTranslationX(startTranX);
        tranXAnima.setValueUpdateListener((animatorValue, v) -> {
            float tranX = startTranX + (endTranX - startTranX) * v;
            pagerLayout.setTranslationX(tranX);
        });
        AnimatorValue tranYAnima = new AnimatorValue();
        tranYAnima.setDuration(300);
        tranYAnima.setCurveType(interpolator);
        float startTranY = -diffTranY;
        float endTranY = 0;
        pagerLayout.setTranslationY(startTranY);
        tranYAnima.setValueUpdateListener((animatorValue, v) -> {
            float tranY = startTranY + (endTranY - startTranY) * v;
            pagerLayout.setTranslationY(tranY);
        });
        AnimatorGroup animatorGroup = new AnimatorGroup();
        animatorGroup.setDuration(300);
        animatorGroup.setCurveType(interpolator);
        AnimatorGroup.Builder builder = animatorGroup.build();
        if (leftTranXAnima != null && rightTranXAnima != null) {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranXAnima, tranYAnima, leftTranXAnima, rightTranXAnima);
        } else if (leftTranXAnima != null) {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranXAnima, tranYAnima, leftTranXAnima);
        } else if (rightTranXAnima != null) {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranXAnima, tranYAnima, rightTranXAnima);
        } else {
            builder.addAnimators(scaleXAnima, scaleYAnima, tranXAnima, tranYAnima);
        }
        animatorGroup.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                if (onSpinMenuStateChangeListener != null) {
                    onSpinMenuStateChangeListener.onMenuClosed();
                }

                // 菜单关闭后，设置 spinMenuLayout 隐藏，菜单状态更新为 MENU_STATE_CLOSED
                spinMenuLayout.setVisibility(Component.HIDE);
                spinMenuLayout.onRefreshed(spinMenuLayout);
                spinMenu.updateMenuState(SpinMenu.MENU_STATE_CLOSED);

                ClickUtils.setChildClickable(pagerLayout, true);
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        animatorGroup.start();
    }
}
